Completed
Push — master ( bbd6f2...66200a )
by Dongxin
26s
created

mjsonviewer.js ➔ onGot   F

Complexity

Conditions 14
Paths 768

Size

Total Lines 279

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
c 1
b 0
f 0
nc 768
nop 1
dl 0
loc 279
rs 2.4369

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like mjsonviewer.js ➔ onGot often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
//////////////////////////////////////////////////////////////////////////////////////
2
// Copyright © 2017 TangDongxin
3
//
4
// Permission is hereby granted, free of charge, to any person obtaining
5
// a copy of this software and associated documentation files (the "Software"),
6
// to deal in the Software without restriction, including without limitation
7
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
// and/or sell copies of the Software, and to permit persons to whom the
9
// Software is furnished to do so, subject to the following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
//////////////////////////////////////////////////////////////////////////////////////
22
23
var bgColor, intColor, strColor, keyColor, defaultColor;
24
var fontStyle;
25
var strictOnly;
26
27
function onError(error) {
28
    console.log(error);
29
}
30
31
function onGot(result) {
32
    if (result[0]) {
33
        fontStyle    = result[0].fontStyle    || "Consolas";
34
        bgColor      = result[0].bgColor      || "#FDF6E3";
35
        intColor     = result[0].intColor     || "#657A81";
36
        strColor     = result[0].strColor     || "#2AA198";
37
        keyColor     = result[0].keyColor     || "#B58900";
38
        defaultColor = result[0].defaultColor || "#586E75";
39
40
        strictOnly   = result[0].strictOnly   || false;
41
    } else {
42
        fontStyle    = result.fontStyle    || "Consolas";
43
        bgColor      = result.bgColor      || "#FDF6E3";
44
        intColor     = result.intColor     || "#657A81";
45
        strColor     = result.strColor     || "#2AA198";
46
        keyColor     = result.keyColor     || "#B58900";
47
        defaultColor = result.defaultColor || "#586E75";
48
49
        strictOnly   = result.strictOnly   || false;
50
    }
51
52
    var str, jsonpMatch, hovered, tag,
53
        chrome = this.chrome || this.browser,
54
        jsonRe = /^\s*(?:\[\s*(?=-?\d|true|false|null|["[{])[^]*\]|\{\s*"[^]+\})\s*$/,
55
        div    = document.createElement("div"),
56
        body   = document.body,
57
        first  = body && body.firstChild,
58
        mod    = /Mac|iPod|iPhone|iPad|Pike/.test(navigator.platform) ? "metaKey" : "ctrlKey",
59
        rand   = Math.random().toString(36).slice(2),
60
        HOV    = "H" + rand,
61
        DIV    = "D" + rand,
62
        KEY    = "K" + rand,
63
        STR    = "S" + rand,
64
        BOOL   = "B" + rand,
65
        ERR    = "E" + rand,
66
        COLL   = "C" + rand;
67
68
    function reconvert(str){
69
        str = str.replace(/(\\u)(\w{1,4})/gi, function($0) {
70
            return (String.fromCharCode(parseInt((escape($0).replace(/(%5Cu)(\w{1,4})/g, "$2")), 16)));
71
        });
72
        str = str.replace(/(&#x)(\w{1,4});/gi, function($0) {
73
            return String.fromCharCode(parseInt(escape($0).replace(/(%26%23x)(\w{1,4})(%3B)/g, "$2"),16));
74
        });
75
        str = str.replace(/(&#)(\d{1,6});/gi, function($0) {
76
            return String.fromCharCode(parseInt(escape($0).replace(/(%26%23)(\d{1,6})(%3B)/g, "$2")));
77
        });
78
79
        return str;
80
    }
81
82
    function units(size) {
83
        return size > 1048576 ? (0|(size / 1048576)) + "MB" :
84
            size > 1024 ? (0|(size / 1024)) + "KB" :
85
            size + "B";
86
    }
87
88
    function fragment(a, b) {
89
        var frag = document.createDocumentFragment();
90
        frag.appendChild(document.createTextNode(a));
91
        if (b) {
92
            frag.appendChild(div.cloneNode());
93
            frag.appendChild(document.createTextNode(b));
94
        } else {
95
            frag.appendChild(document.createElement("br"));
96
        }
97
        return frag;
98
    }
99
100
    function change(node, query, name, set) {
101
        var list = node.querySelectorAll(query), i = list.length;
102
        for (; i--; ) list[i].classList[set ? "add" : "remove"](name);
103
    }
104
105
    function changeSiblings(node, name, set) {
106
        var tmp, i = 0, query = [];
107
108
        for (; node && node.tagName === "I"; ) {
109
            tmp = node.previousElementSibling;
110
            if (tmp && tmp.className == KEY) {
111
                query.unshift(".D" + rand + ">i.I" + rand + "[data-key='" + node.dataset.key + "']");
112
            } else if (query[0]) {
113
                query.unshift(".D" + rand + ">i.I" + rand);
114
            } else {
115
                for (; tmp; tmp = tmp.previousElementSibling) if (tmp.tagName === "BR") i++;
116
                query.unshift(".D" + rand + ">" + (i ? "br:nth-of-type(" + i + ")+i.I" + rand : "i.I" + rand + ":first-child"));
117
            }
118
            node = node.parentNode && node.parentNode.previousElementSibling;
119
        }
120
        if (!query[1]) return;
121
        query[0] = ".R" + rand + ">i.I" + rand;
122
        change(document, query.join("+"), name, set);
123
    }
124
125
    function keydown(e) {
126
        if (hovered) {
127
            e.preventDefault();
128
            if (e.altKey) {
129
                changeSiblings(hovered, HOV, 1);
130
            } else if (e[mod]) {
131
                change(hovered.nextSibling, "i.I" + rand, HOV, 1);
132
            }
133
        }
134
    }
135
136
    function init() {
137
        tag = document.createElement("style");
138
        tag.textContent = [
139
            '.R', ',.D', '{font:16px ' + fontStyle + '}' +
140
            '.D', '{margin-left:6px; padding-left:1em; margin-top: 1px; border-left:1px dashed; border-color: #93A1A1;}' +
141
            '.X', '{border:1px solid #ccc; padding:1em}' +
142
            'a.L', '{text-decoration:none}' +
143
            'a.L', ':hover,a.L', ':focus{text-decoration:underline}' +
144
            'i.I', '{cursor:pointer;color:#ccc}' +
145
            'i.H', ',i.I', ':hover{text-shadow: 1px 1px 3px #999; color:#333}'+
146
            'i.I', ':before{content:" ▼ "}' +
147
            'i.C', ':before{content:" ▶ "}' +
148
            'i.I', ':after{content:attr(data-content)}' +
149
            'i.C', '+.D', '{width:1px; height:1px; margin:0; padding:0; border:0; display:inline-block; overflow:hidden}' +
150
            '.S', '{color:' + strColor + '}' + // string
151
            '.K', '{color:' + keyColor + '}' + // key
152
            '.E', '{color:#BCADAD}' + // error
153
            '.B', '{color:' + intColor + '}' + // number and bool
154
            '.E', ',.B', '{font-style: italic}' + // number bold
155
            'h3.E', '{margin:0 0 1em}'
156
        ].join(rand);
157
158
        tag.textContent = tag.textContent + 'body {background: ' + bgColor + '; color:' + defaultColor + ';}';
159
160
        div.classList.add(DIV);
161
        document.head.appendChild(tag);
162
        document.addEventListener("keydown", keydown);
163
        document.addEventListener("keyup", function(e) {
164
            if (hovered) change(document, "." + HOV, HOV);
165
        })
166
        document.addEventListener("mouseover", function(e) {
167
            if (e.target.tagName === "I") {
168
                hovered = e.target;
169
                keydown(e);
170
            }
171
        })
172
        document.addEventListener("mouseout", function(e) {
173
            if (hovered) {
174
                change(document, "." + HOV, HOV);
175
                hovered = null;
176
            }
177
        })
178
    }
179
180
    function draw(str, to, first, box) {
181
        tag || init();
182
183
        var re = /("(?:((?:https?|file):\/\/(?:\\?\S)+?)|(?:\\?.)*?)")\s*(:?)|-?\d+\.?\d*(?:e[+-]?\d+)?|true|false|null|[[\]{},]|(\S[^-[\]{},"\d]*)/gi
184
            , node = div.cloneNode()
185
            , link = document.createElement("a")
186
            , span = document.createElement("span")
187
            , info = document.createElement("i")
188
            , colon = document.createTextNode(": ")
189
            , comma = fragment(",")
190
            , path = []
191
            , cache = {
192
                "{": fragment("{", "}"),
193
                "[": fragment("[", "]")
194
            };
195
196
        node.className = "R" + rand + (box ? " " + box : "");
197
198
        link.classList.add("L" + rand);
199
        info.classList.add("I" + rand);
200
201
        to.addEventListener("click", function(e) {
202
            var target = e.target, open = target.classList.contains(COLL);
203
            if (target.tagName == "I") {
204
                if (e.altKey) {
205
                    changeSiblings(target, COLL, !open);
206
                } else if (e[mod]) {
207
                    open = target.nextSibling.querySelector("i");
208
                    if (open) change(target.nextSibling, "i", COLL, !open.classList.contains(COLL));
209
                } else {
210
                    target.classList[open ? "remove" : "add"](COLL);
211
                }
212
            }
213
        }, true);
214
215
        to.replaceChild(box = node, first);
216
        loop(str, re);
217
218
        function loop(str, re) {
219
            str = reconvert(str);
220
            var match, val, tmp, i = 0, len = str.length;
221
            try {
222
                for (; match = re.exec(str); ) {
223
                    val = match[0];
224
                    if (val == "{" || val == "[") {
225
                        path.push(node);
226
                        node.appendChild(cache[val].cloneNode(true));
227
                        node = node.lastChild.previousSibling;
228
                        node.len = 1;
229
                        node.start = re.lastIndex;
230
                    } else if ((val == "}" || val == "]") && node.len) {
231
                        if (node.childNodes.length) {
232
                            tmp = info.cloneNode();
233
                            tmp.dataset.content = node.len + (
234
                                node.len == 1 ?
235
                                (val == "]" ? " item, " : " property, ") :
236
                                (val == "]" ? " items, " : " properties, ")
237
                            ) + units(re.lastIndex - node.start + 1);
238
239
                            if ((val = node.previousElementSibling) && val.className == KEY) {
240
                                tmp.dataset.key = reconvert(val.textContent.slice(1, -1).replace(/'/, "\\'"));
241
                            }
242
                            node.parentNode.insertBefore(tmp, node);
243
                        } else {
244
                            node.parentNode.removeChild(node);
245
                        }
246
                        node = path.pop();
247
                    } else if (val == ",") {
248
                        node.len += 1;
249
                        node.appendChild(comma.cloneNode(true));
250
                    } else {
251
                        if (match[2]) {
252
                            tmp = link.cloneNode();
253
                            tmp.href = match[2].replace(/\\"/g, '"');
254
                        } else {
255
                            tmp = span.cloneNode();
256
                        }
257
                        tmp.textContent = match[1] || val;
258
                        tmp.classList.add(match[3] ? KEY : match[1] ? STR : match[4] ? ERR : BOOL);
259
                        node.appendChild(tmp);
260
                        if (match[3]) {
261
                            node.appendChild(colon.cloneNode());
262
                        }
263
                    }
264
                    if (++i > 1000) {
265
                        document.title = (0|(100*re.lastIndex/len)) + "% of " + units(len);
266
                        return setTimeout(function() { loop(str, re) });
267
                    }
268
                }
269
                document.title = ""
270
                JSON.parse(str)
271
            } catch(e) {
272
                tmp = document.createElement("h3");
273
                tmp.className = ERR;
274
                tmp.textContent = e;
275
                box.insertBefore(tmp, box.firstChild);
276
            }
277
        }
278
    }
279
280
    if (strictOnly) {
281
        // only render when the contentType is json
282
        if (/[+\/]json$/i.test(document.contentType))
283
            draw(str, body, first)
284
        }
285
    } else {
286
        // check whether the content is json or like json
287
        if (first
288
            && (first.tagName == "PRE"
289
                && first == body.lastElementChild
290
                || first == body.lastChild
291
                && first.nodeType == 3)
292
            && (str = first.textContent)
293
            && (/[+\/]json$/i.test(document.contentType)
294
                || (jsonpMatch = /^\s*((?:\/\*\*\/\s*)?([$a-z_][$\w]*)\s*(?:&&\s*\2\s*)?\()([^]+)(\)[\s;]*)$/i.exec(str))
295
                && jsonRe.test(jsonpMatch[3]) || jsonRe.test(str)))
296
        {
297
            if (jsonpMatch) {
298
                str = jsonpMatch[3]
299
                body.replaceChild(fragment(jsonpMatch[1], jsonpMatch[4]), first)
300
                first = body.lastChild.previousSibling
301
            }
302
            draw(str, body, first)
303
        }
304
    }
305
306
    chrome.runtime.onMessage.addListener(function(req, sender, sendResponse) {
307
        var node,
308
            sel   = window.getSelection(),
309
            range = sel.rangeCount && sel.getRangeAt(0),
310
            str   = range && range.toString()
311
312
        if (!str) return
313
314
        if (req.op === "formatSelection") {
315
            node = document.createElement("div")
316
            range.deleteContents()
317
            range.insertNode(node)
318
            sel.removeAllRanges()
319
            draw(str, node.parentNode, node, "X" + rand)
320
        }
321
    })
322
}
323
324
var getting = browser.storage.local.get();
325
getting.then(onGot, onError);
326
327